package leeon.mobile.server.bbscache;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import leeon.mobile.BBSBrowser.models.BlockObject;
import leeon.mobile.BBSBrowser.models.BoardObject;
import leeon.mobile.BBSBrowser.models.DocObject;
import leeon.mobile.server.bbscache.entity.Doc;
import leeon.mobile.server.bbscache.entity.OffsetIndex;

/**
 * 获取数据进行渲染的服务
 * 返回的都是xml的body，不包括gb的编码和xsd
 * @author leeon
 */
public class BBSViewService {
	
	public static final String SESSION_XML_BODY = "<session m=''><p>    </p><u></u><f></f></session>\n";
	
	public String top10() {
		StringBuffer xml = new StringBuffer();
		List<DocObject> list = CacheService.getOrCreateTopTen(false, true);
		xml.append("<bbstop10>\n");
		xml.append(SESSION_XML_BODY);
		//<top board='TV' owner='hatsuki' count='266' gid='3085550192'>童鞋们不是说在这里讨论三生三世么？</top>
		for (DocObject doc : list) {
			xml.append("<top board='").append(doc.getBoard().getName())
			.append("' owner='").append(doc.getAuthor())
			.append("' count='").append(doc.getDocNumber())
			.append("' gid='").append(doc.getId())
			.append("'>")
			.append(doc.getTitle().replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;"))
			.append("</top>\n");
		}
		xml.append("</bbstop10>");
		return xml.toString();
	}
	
	public String sec() {
		StringBuffer xml = new StringBuffer();
		List<BlockObject> list = CacheService.getOrCreateAll(false);
		xml.append("<bbssec>\n");
		xml.append(SESSION_XML_BODY);
		//<sec id='0' desc='BBS 系统 [站内]'>
		//<brd name='SysOp' desc='站长工作室' />
		for (BlockObject block : list) {
			xml.append("<sec id='").append(block.getId())
			.append("' desc='").append(block.getName())
			.append("'>");
			for (BoardObject board : block.getRecommendBoardList()) {
				xml.append("<brd name='").append(board.getName())
				.append("' desc='").append(board.getCh())
				.append("' />");
			}
			xml.append("</sec>");
		}
		xml.append("</bbssec>");
		return xml.toString();
	}
	
	public String all() {
		StringBuffer xml = new StringBuffer();
		List<BlockObject> list = CacheService.getOrCreateAll(false);
		xml.append("<bbsall>\n");
		xml.append(SESSION_XML_BODY);
		for (BlockObject block : list) {
			allBoard(block.getAllBoardList(), xml);
		}
		xml.append("</bbsall>");
		return xml.toString();
	}
	
	//递归刷新版面
	private void allBoard(List<BoardObject> list, StringBuffer xml) {
		for (BoardObject b : list) {
			if (b.isDir()) {
				allBoard(b.getChildBoardList(), xml);
			}
			//<brd dir='0' title='BM_Home' cate='[站内]' desc='版主之家' bm='BMS' />
			xml.append("<brd dir='")
			.append(b.isDir()?"1":"0")
			.append("' title='").append(b.getName())
			.append("' cate='").append(b.getType())
			.append("' desc='").append(b.getCh())
			.append("' bm='").append(b.getMaster())
			.append("' />");
		}
	}
	
	public String boa(String boardName, String s) {
		StringBuffer xml = new StringBuffer();
		List<BlockObject> list = CacheService.getOrCreateAll(false);
		
		List<BoardObject> ret = null;
		for (BlockObject block : list) {
			if (s != null && s.equals(block.getId())) {
				xml.append("<bbsboa link='doc' title='").append(block.getName()).append("'>\n");
				ret = block.getAllBoardList();
			} else if (boardName != null) {
				ret = boaBoard(block.getAllBoardList(), boardName, xml); 
			}
			if (ret != null) break;
		}
		
		if (ret == null) return null;
		//<bbsboa link='doc'  title='院系风采'>
		//<bbsboa link='doc'  dir= '1' title='软件学院'
		//<brd dir='0' title='FDU_C.D.E.' cate='[院系]' desc='网络教育学院 ' bm='' read='1' count='3502' />
		//").append("
		for (BoardObject b : ret) {
			xml.append("<brd dir='").append(b.isDir()?"1":"0")
			.append("' title='").append(b.getName())
			.append("' cate='").append(b.getType())
			.append("' desc='").append(b.getCh())
			.append("' bm='").append(b.getMaster())
			.append("' read='1' count='").append(b.getDocNumber())
			.append("' />");
		}
		xml.append(SESSION_XML_BODY);
		xml.append("</bbsboa>");
		return xml.toString();
	}
	
	private List<BoardObject> boaBoard(List<BoardObject> list, String boardName, StringBuffer xml) {
		for (BoardObject board : list) {
			if (board.isDir()) {
				if (board.getName().equals(boardName)) {
					xml.append("<bbsboa link='doc' dir='1' title='").append(board.getCh()).append("'>\n");
					return board.getChildBoardList();
				} else {
					List<BoardObject> ret = boaBoard(board.getChildBoardList(), boardName, xml);
					if (ret != null) return ret;
				}
			}
		}
		return null;
	}
	
	public String doc(String boardName, Long bid, int start) {
		return docAll(boardName, bid, start, false);
	}
	
	public String tdoc(String boardName, Long bid, int start) {
		return docAll(boardName, bid, start, true);
	}

	private String docAll(String boardName, Long bid, int start, boolean title) {
		if (boardName == null && bid == null) return null;
		BoardObject b = Utils.findBoard(boardName, bid);
		
		if (b == null) return null;
		if (b.getId() == null) return null;
		bid = Long.valueOf(b.getId());
		
		if (title && b.getTotalG() == 0) return null;
		if (!title && b.getTotal() == 0) return null;
		int total = title?b.getTotalG():b.getTotal();
		total = total-20+1;
		if (start < 1 || start > total) {
			if (total > 0) start = total;
			else start = 1;
		}
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		String sql;int begin;Object[] p;
		if (title) {//主题模式因为文章数相对少，不做offset index的处理，倒序range即可
			sql = "select from leeon.mobile.server.bbscache.entity.Doc where " +
				"keyG >= bidParam && keyG < bidParamM " + 
				"parameters Long bidParam, Long bidParamM order by keyG desc";
			begin = (title?b.getTotalG():b.getTotal()) - (start+20-1);//use desc
			if (begin < 0) begin = 0;
			p = Doc.creatBoardFilterG(bid);
		} else {//非主题模式，使用offset index来进行查询
			OffsetIndex index = CacheService.getOrCreateIndex(b, false);
			sql = "select from leeon.mobile.server.bbscache.entity.Doc where " +
				"key >= bidParam && key < bidParamM " + 
				"parameters Long bidParam, Long bidParamM order by key";
			begin = 0;//始终为0
			p = Doc.creatBoardFilter(bid, index.getValue(start-1));//根据start-1为offset值来获取 start key
		}
				
		List<Doc> list = new ArrayList<Doc>();
		try {
			Query query = pm.newQuery(sql);
			query.setRange(begin, begin+20);
			//query.setRange(start-1, start+20-1);
			
			@SuppressWarnings("unchecked")
			List<Doc> results = (List<Doc>) query.executeWithArray(p);
			if (results != null) 
				if (title) for (Doc d : results) list.add(0, d);// title use desc
				else list.addAll(results);//no title use asc
		} finally {
			pm.close();
		}
		
//		if (!title) {
//			docSticky(bid, list);
//		}
		
		return docXml(list, b, title, start);
	}	

/**	
	private void docSticky(Long bid, List<Doc> list) {
		if (bid == null) return;
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		String sql = "select from leeon.mobile.server.bbscache.entity.Doc where sticky == true ";
		sql += "&& bid == bidParam parameters Long bidParam ";
		sql += "order by fid";
		
		try {
			Query query = pm.newQuery(sql);
			@SuppressWarnings("unchecked")
			List<Doc> results = (List<Doc>) query.execute(bid);
			list.addAll(results);
		} finally {
			pm.close();
		}
	}
**/	

	private String docXml(List<Doc> list, BoardObject board, boolean title, int start) {
		StringBuffer xml = new StringBuffer();
		xml.append("<bbsdoc>");
		xml.append(SESSION_XML_BODY);
		//<po m='+' owner='melgibson' time= '2011-11-22T23:27:07' id='64300'>rw如果请朋友从美国寄机器回来</po>
		//<po sticky='1' m='m' owner='merryruan' time= '2007-02-13T19:48:23' id='12369'>Mac版面FAQ</po>
		//<brd title='Mac' desc='苹果电脑' bm='RottenOrange' total='1724' start='1705' bid='401' page='20' link='t'/>
		//").append("
		for (Doc d : list) {
			String owner = d.getAuthor();
			int e = owner.indexOf(' ');
			if (e != -1) owner = owner.substring(0,  e);
			
			xml.append("<po")
			//.append(d.isSticky()?" sticky='1'":"")
			.append(" m='+' owner='").append(owner)
			.append("' time= '").append(Utils.dateToString(d.getDate()).replace(' ', 'T'))
			.append("' id='").append(d.getFid())
			.append("'>").append(d.getTitle())
			.append("</po>\n");
		}
		
		xml.append("<brd title='").append(board.getName())
		.append("' desc='").append(board.getCh())
		.append("' bm='").append(board.getMaster())
		.append("' total='").append(title?board.getTotalG():board.getTotal())
		.append("' start='").append(start==0?board.getTotal()-20+1:start)
		.append("' bid='").append(board.getId())
		.append("' page='20' link='").append(title?"t":"")
		.append("'/>\n");
		xml.append("</bbsdoc>");
		return xml.toString();
	}
	
	//a=p上一篇,n下一篇,a下一楼
	public String con(String boardName, Long bid, Long fid, String a, boolean n) {
		if (boardName == null && bid == null) return null;
		BoardObject b = Utils.findBoard(boardName, bid);
		
		if (b == null) return null;
		if (b.getId() == null) return null;
		bid = Long.valueOf(b.getId());

		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			if (a != null) {
				
				String sql;
				List<Object> p;
				if ("n".equals(a)) {
					sql = "select from leeon.mobile.server.bbscache.entity.Doc where " + 
							"key > keyParam parameters Long keyParam order by key";
					Object p1 = Doc.createKey(bid, fid);
					p = Arrays.asList(p1);
				} else if ("p".equals(a)) {
					//为了不建立索引，这里有一定的概率拿到不
					//modify must has key desc index
					// modify 为 use offset index 
					sql = "select from leeon.mobile.server.bbscache.entity.Doc where " + 
							"key == keyParam parameters Long keyParam";
					OffsetIndex index = CacheService.getOrCreateIndex(b, false);
					Object p1 = index.previous(Doc.createKey(bid, fid));//通过索引找前一个
					p = Arrays.asList(p1);
				} else {//a
					Doc d = pm.getObjectById(Doc.class, Doc.createKey(bid, fid));
					sql = "select from leeon.mobile.server.bbscache.entity.Doc where " + 
						"key > keyParam && keyG == gidParam " +
						"parameters Long keyParam, Long gidParam order by key";
					Object p1 = d.getKey();
					Object p2 = Doc.createKeyG(bid, d.getGid(), false);
					p = Arrays.asList(p1, p2);
				}
				
				Query query = pm.newQuery(sql);
				query.setRange(0, 1);
				
				@SuppressWarnings("unchecked")
				List<Doc> results2 = (List<Doc>) query.executeWithArray(p.toArray());
				if (results2 == null || results2.size() == 0) return null;
				fid = results2.get(0).getFid();
			}
		} catch (JDOObjectNotFoundException e) {
			return null;
		} finally {
			pm.close();
		}
		return conAll(b, fid, false, null, null, n);
	}
	
	//a=下一主题,b上一主题,n向后展开,p向前展开
	public String tcon(String boardName, Long bid, Long fid, Long gid, String a, boolean n) {
		if (boardName == null && bid == null) return null;
		BoardObject b = Utils.findBoard(boardName, bid);
		
		if (b == null) return null;
		if (b.getId() == null) return null;
		bid = Long.valueOf(b.getId());
		
		if (a != null) {
			if (gid == null) {
				PersistenceManager pm = PMF.get().getPersistenceManager();
				try {
					String sql;
					if ("a".equals(a)) {
						sql = "select from leeon.mobile.server.bbscache.entity.Doc where " +
							"keyG > gidParam && keyG < gidParamM " +
							"parameters Long gidParam, Long gidParamM order by keyG";
					} else {
						sql = "select from leeon.mobile.server.bbscache.entity.Doc where " +
							"keyG < gidParam && keyG >= gidParamM " +
							"parameters Long gidParam, Long gidParamM order by keyG desc";
					}
					Query query = pm.newQuery(sql);
					query.setRange(0, 1);
					
					Long p1 = Doc.createKeyG(bid, fid, true);
					Long p2 = "a".equals(a)?Doc.createBoardKey(bid-1):Doc.createBoardKeyG(bid);
					@SuppressWarnings("unchecked")
					List<Doc> results = (List<Doc>) query.execute(p1, p2);
					if (results == null || results.size() == 0) return null;
					
					fid = results.get(0).getFid();
				} finally {
					pm.close();
				}
			}
		}
		return conAll(b, fid, true, gid, a, n);
	}
	
	private String conAll(BoardObject board, Long fid, boolean title, Long gid, String a, boolean n) {
		if (board.getId() == null) return null;
		Long bid = Long.valueOf(board.getId());
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		String sql = "select from leeon.mobile.server.bbscache.entity.Doc where ";
		List<Object> p;
		if (title && gid != null) {
			if ("n".equals(a)) {
				sql += "keyG.contains(gidParam) && key > fidParam " +
						"parameters Long gidParam, Long fidParam order by key";
			} else if ("p".equals(a)) {
				sql += "keyG.contains(gidParam) && key < fidParam " +
						"parameters Long gidParam, Long fidParam order by key desc";
			}
			Object p1 = Doc.createGdocFilter(bid, gid);
			Object p2 = Doc.createKey(bid, fid);
			p = Arrays.asList(p1, p2);
		} else if (title) {
			sql += "keyG.contains(fidParam) parameters Long fidParam order by key";
			Object p1 = Doc.createGdocFilter(bid, fid);
			p = Arrays.asList(p1);
		} else {
			sql += "key == fidParam parameters Long fidParam";
			Object p1 = Doc.createKey(bid, fid);
			p = Arrays.asList(p1);
		}

		List<Doc> list = new ArrayList<Doc>();
		try {
			Query query = pm.newQuery(sql);
			query.setRange(0, 20);			
			@SuppressWarnings("unchecked")
			List<Doc> results = (List<Doc>) query.executeWithArray(p.toArray());
			
			if (title && gid != null) {
				if ("n".equals(a)) {
					list.addAll(results);
				} else {
					for (Doc d : results) list.add(0, d);
				}
			} else {
				list.addAll(results);
			}
		} finally {
			pm.close();
		}
		
		return conXml(list, title, gid==null?fid:gid, board.getId(), n);
	}
	
	private String conXml(List<Doc> list, boolean title, Long gid, String bid, boolean n) {
		StringBuffer xml = new StringBuffer();
		xml.append(title?"<bbstcon page='20' attach='0'":"<bbscon link='con' anony='0' attach='0'")
			.append(" bid='").append(bid).append("'");
		if (title) xml.append(" gid='").append(gid).append("'");
		xml.append(">");
		xml.append(SESSION_XML_BODY);
		//<bbscon link='con' bid='401' anony='0' attach='1048576'>
		//<bbstcon bid='401' gid='64284' page='20' attach='1048576' last='1'>
		//<po fid='3085263460' reid='3085263253' gid='3085263253' last='1' tlast='1'>
		
		for (Doc d : list) {
			xml.append("<po fid='").append(d.getFid())
			.append("' reid='0'")
			.append(" gid='").append(d.getGid()).append("'>")
			.append(n?d.getNewContent():d.getOldContent())
			.append("</po>\n");
		}
		
		xml.append(title?"</bbstcon>":"</bbscon>");
		return xml.toString();
	}
	public static void main(String[] args) {
	}

}
